﻿using Abp.Authorization;
using Abp.Collections.Extensions;
using Abp.Specifications;
using Abp.UI;
using Paas.App.Interface.Sys.Admin;
using Paas.App.Interface.Sys.Admin.Dtos;
using Paas.App.Interface.Sys.Admin.Messages;
using Paas.Core;
using Paas.Core.Approvals.Entities;
using Paas.Core.Const;
using Paas.Core.Sys.Entities;
using Paas.Core.Sys.Interfaces;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Basefr.App;
using Basefr.Core.Consts.Enums;
using Basefr.Core.Extensions;
using Basefr.Runtime.Extensions;
using Basefr.Runtime.Helpers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Paas.Core.Meta.Entities;
using Paas.Core.Const.Enums;

namespace Paas.App.Sys
{
    [Route("Sys-Admin")]
    [AbpAuthorize()]
    public class SysAdminAppService : AppService, ISysAdminAppService
    {
        private readonly IMainRepository<User, long> _userRepo;
        private readonly IMainRepository<Role> _roleRepo;
        private readonly IMainRepository<Organization> _organRepo;
        private readonly IMainRepository<RolePermission> _rolePermRepo;
        private readonly IMainRepository<RoleUser> _roleUserRepo;
        private readonly IMainRepository<Organization> _organizationRepo;

        private readonly IMainRepository<Approve> _approveRepo;

        private readonly IMainRepository<Application> _applicationRepo;

        private readonly ISysManager _sysManager;

        public SysAdminAppService(
            IMainRepository<User, long> userRepo,
            IMainRepository<Role> roleRepo,
            IMainRepository<Organization> organRepo,
            IMainRepository<RolePermission> rolePermRepo,
            ISysManager sysManager,
            IMainRepository<RoleUser> roleUserRepo, IMainRepository<Organization> organizationRepo, IMainRepository<Approve> approveRepo,
            IMainRepository<Application> applicationRepo)
        {
            _userRepo = userRepo;
            _roleRepo = roleRepo;
            _organRepo = organRepo;
            _rolePermRepo = rolePermRepo;
            _sysManager = sysManager;
            _roleUserRepo = roleUserRepo;
            _organizationRepo = organizationRepo;
            _approveRepo = approveRepo;
            _applicationRepo = applicationRepo;
        }

        [HttpPost(nameof(SearchUser))]
        public virtual SearchUserOutput SearchUser(SearchUserInput input)
        {
            Expression<Func<User, bool>> predicate = p => true;

            //predicate = predicate.StringContains(p => p.Name, input.Name);
            //predicate = predicate.ValueEqualsWhen(p => p.OrganizationId, input.OrganizationId, p => p > 0);
            if (input.OrganizationId > 0)
            {
                predicate = predicate.And(p => p.OrganizationId == input.OrganizationId);
            }

            if (!string.IsNullOrWhiteSpace(input.Name))
            {
                var name = input.Name.Trim();
                predicate = predicate.And(p => p.Name.Contains(name));
            }

            var result = _userRepo.GetAll()
                .Include(p => p.Organization.Parent.Parent.Parent.Parent.Parent)
                .Include(p => p.Roles).ThenInclude(p => p.Role.Permissions)
                .Where(predicate)
                .OrderBy(p => p.Id)
                .GetPage(input.SkipCount, input.MaxResultCount, out var total, out var isOverPaged)
                .ToList();

            return new SearchUserOutput { Items = ObjectMapper.Map<List<UserDto>>(result), TotalCount = total, IsOverPaged = isOverPaged };
        }

        [HttpPost(nameof(SaveUser))]
        public virtual SaveUserOutput SaveUser(SaveUserInput input)
        {
            _sysManager.SaveUser(ObjectMapper.Map<User>(input.Item));
            return new SaveUserOutput();
        }

        [HttpPost(nameof(ResetUserPassword))]
        public virtual ResetUserPasswordOutput ResetUserPassword(ResetUserPasswordInput input)
        {
            var user = _userRepo.Get(input.Id);

            user.PasswordSalt = Guid.NewGuid().ToString("N");
            user.Password = HashHelper.Hash(user.UserName, user.PasswordSalt);

            return new ResetUserPasswordOutput();
        }

        [HttpPost(nameof(DeleteUser))]
        public virtual DeleteUserOutput DeleteUser(DeleteUserInput input)
        {
            var user = _userRepo.Get(input.Id);
            var openApproves = _approveRepo.GetAll().Where(p => p.Steps.Any(s => s.OperatorId == user.Id) && (p.State == EnumApproveState.Pending || p.State == EnumApproveState.OnGoing)).ToList();

            if (openApproves.Any())
            {
                var names = openApproves.Select(p => p.Type.Description()).JoinAsString("，");
                throw new UserFriendlyException($"此用户存在尚未结束的 {names} 流程，不能删除");
            }

            _userRepo.Delete(user);

            return new DeleteUserOutput();
        }

        [HttpPost(nameof(SearchRoleForUser))]
        public virtual SearchRoleForUserOutput SearchRoleForUser(SearchRoleForUserInput input)
        {
            var roles = _roleRepo.GetAll().OrderBy(p => p.Id).ToList();
            var user = _userRepo.GetAll().Include(p => p.Roles).FirstOrDefault(input.UserId);

            if (user == null)
            {
                throw new UserFriendlyException("用户无效");
            }

            var result = ObjectMapper.Map<List<RoleForUserDto>>(roles);

            //if (user.Roles.Any())
            //{
            result.ForEach(r =>
            {
                var grant = user.Roles?.FirstOrDefault(ur => ur.RoleId == r.Id);
                r.IsGranted = grant != null;
                r.IsPreDefined = grant?.IsPreDefined ?? false;
            });
            //}

            return new SearchRoleForUserOutput { Items = result };
        }

        [HttpPost(nameof(AssignUserToRole))]
        public virtual AssignUserToRoleOutput AssignUserToRole(AssignUserToRoleInput input)
        {
            var roleUser = _roleUserRepo.FirstOrDefault(p => p.UserId == input.UserId && p.RoleId == input.RoleId);
            if (roleUser == null)
            {
                _roleUserRepo.Insert(new RoleUser
                {
                    RoleId = input.RoleId,
                    UserId = input.UserId
                });

                CurrentUnitOfWork.SaveChanges();
            }

            return new AssignUserToRoleOutput();
        }

        [HttpPost(nameof(RemoveUserFromRole))]
        public virtual RemoveUserFromRoleOutput RemoveUserFromRole(RemoveUserFromRoleInput input)
        {
            var roleUser = _roleUserRepo.FirstOrDefault(p => p.UserId == input.UserId && p.RoleId == input.RoleId);
            if (roleUser != null)
            {
                _roleUserRepo.Delete(roleUser);

                CurrentUnitOfWork.SaveChanges();
            }

            return new RemoveUserFromRoleOutput();
        }

        [HttpPost(nameof(SearchRole))]
        public virtual SearchRoleOutput SearchRole(SearchRoleInput input)
        {
            Expression<Func<Role, bool>> predicate = p => true;

            //predicate = predicate.StringContains(p => p.Name, input.Name);
            if (!string.IsNullOrWhiteSpace(input.Name))
            {
                var name = input.Name.Trim();
                predicate = predicate.And(p => p.Name.Contains(name));
            }

            var result = _roleRepo.GetAll()
                .Include(p => p.Permissions)
                .Where(predicate)
                .OrderBy(p => p.Id)
                .GetPage(input.SkipCount, input.MaxResultCount, out var total, out var isOverPaged);

            //系统应用权限
            var allPermissions = PermissionHelper.GetList<Permissions>();
            //租户App应用权限
            var appPermissions = _applicationRepo.GetAllList()?.Where(p => p.CurrentStatus==MetaStatus.Released)?.Select(p => new KeyValuePair<string, string>(p.Name, p.Label)).ToList();
            if (appPermissions.Any())
                allPermissions.AddRange(appPermissions);

            var res = ObjectMapper.Map<List<RoleDto>>(result);
            res.ForEach(p =>
            {
                //获取角色拥有权限的名称
                p.PermissionNames=p.Permissions?.Select(p => allPermissions?.FirstOrDefault(q => q.Key==p.Permission).Value).JoinAsString("，") ?? "";
            });

            return new SearchRoleOutput
            {
                Items = res,
                TotalCount = total,
                IsOverPaged = isOverPaged
            };
        }

        [HttpPost(nameof(SaveRole))]
        public virtual SaveRoleOutput SaveRole(SaveRoleInput input)
        {
            _sysManager.SaveRole(ObjectMapper.Map<Role>(input.Item));
            return new SaveRoleOutput();
        }

        [HttpPost(nameof(DeleteRole))]
        public virtual DeleteRoleOutput DeleteRole(DeleteRoleInput input)
        {
            var role = _roleRepo.GetAllIncluding(p => p.Users).FirstOrDefault(input.Id);

            if (role == null)
            {
                throw new UserFriendlyException("角色无效");
            }

            if (role.IsPreDefined)
            {
                throw new UserFriendlyException("不能删除系统预定义角色");
            }

            if (role.Users?.Any() ?? false)
            {
                throw new UserFriendlyException("此角色已经分配给用户，不能删除");
            }

            _roleRepo.Delete(role);

            CurrentUnitOfWork.SaveChanges();

            return new DeleteRoleOutput();
        }

        [HttpPost(nameof(SearchPermissionForRole))]
        public virtual SearchPermissionForRoleOutput SearchPermissionForRole(SearchPermissionForRoleInput input)
        {
            var role = _roleRepo.GetAll().FirstOrDefault(p => p.Id == input.Id);
            if (role == null)
            {
                throw new UserFriendlyException("角色无效");
            }

            var grantedPermissions = _rolePermRepo.GetAll().Where(p => p.RoleId == role.Id).ToList();

            //系统应用权限
            var allPermissions = PermissionHelper.GetList<Permissions>().Select(p => new PermissionForRoleDto { Permission = p.Key, PermissionName = p.Value }).ToList();
            //租户App应用权限
            var appPermissions = _applicationRepo.GetAllList()?.Where(p => p.CurrentStatus==MetaStatus.Released).Select(p => new PermissionForRoleDto { Permission = p.Name, PermissionName = p.Label }).ToList();
            if (appPermissions.Any())
                allPermissions.AddRange(appPermissions);

            allPermissions.ForEach(p =>
            {
                var granted = grantedPermissions.FirstOrDefault(a => a.Permission == p.Permission);

                p.IsGranted = granted != null;
                p.RoleId = granted?.RoleId ?? 0;
                p.IsPreDefined = granted?.IsPreDefined ?? false;
            });

            return new SearchPermissionForRoleOutput { Items = allPermissions };
        }

        [HttpPost(nameof(AssignRolePermission))]
        public virtual AssignRolePermissionOutput AssignRolePermission(AssignRolePermissionInput input)
        {
            var rolePermission = _rolePermRepo.FirstOrDefault(p => p.RoleId == input.RoleId && p.Permission == input.Permission);
            if (rolePermission == null)
            {
                _rolePermRepo.Insert(new RolePermission
                {
                    RoleId = input.RoleId,
                    Permission = input.Permission
                });

                CurrentUnitOfWork.SaveChanges();
            }

            return new AssignRolePermissionOutput();
        }

        [HttpPost(nameof(RemoveRolePermission))]
        public virtual RemoveRolePermissionOutput RemoveRolePermission(RemoveRolePermissionInput input)
        {
            var rolePermission = _rolePermRepo.FirstOrDefault(p => p.RoleId == input.RoleId && p.Permission == input.Permission);
            if (rolePermission != null)
            {
                _rolePermRepo.Delete(rolePermission);

                CurrentUnitOfWork.SaveChanges();
            }

            return new RemoveRolePermissionOutput();
        }

        [HttpPost(nameof(SearchOrganization))]
        public virtual SearchOrganizationOutput SearchOrganization(SearchOrganizationInput input)
        {
            var result = _organRepo.GetAll().ToList().OrderByLevel();

            return new SearchOrganizationOutput { Items = ObjectMapper.Map<List<OrganizationDto>>(result) };
        }

        [HttpPost(nameof(SaveOrganization))]
        public virtual SaveOrganizationOutput SaveOrganization(SaveOrganizationInput input)
        {
            _sysManager.SaveOrganization(ObjectMapper.Map<Organization>(input.Item));

            return new SaveOrganizationOutput();
        }

        [HttpPost(nameof(DeleteOrganization))]
        public virtual DeleteOrganizationOutput DeleteOrganization(DeleteOrganizationInput input)
        {
            var organization = _organizationRepo.GetAll().Include(p => p.Children).FirstOrDefault(p => p.Id == input.Id);

            if (organization == null)
            {
                throw new UserFriendlyException("部门无效");
            }

            if (organization.IsPreDefined)
            {
                throw new UserFriendlyException("不能删除系统预定义部门");
            }

            if (organization.Children != null && organization.Children.Any())
            {
                throw new UserFriendlyException("当前部门包含下级部门，无法删除");
            }

            var existUser = _userRepo.GetAll().Any(p => p.OrganizationId == input.Id);

            if (existUser)
            {
                throw new UserFriendlyException("当前部门包含用户，无法删除");
            }

            _organizationRepo.Delete(organization);

            CurrentUnitOfWork.SaveChanges();

            return new DeleteOrganizationOutput();
        }
    }
}

